"""项目依赖镜像源配置工具

自动配置 Maven 和 Gradle 项目使用国内镜像源，提高依赖下载速度。

用法:
    python gfw_project.py

功能:
    - 自动检测项目类型（Maven/Gradle）
    - 配置 Maven settings.xml 使用阿里云镜像
    - 配置 Gradle 项目使用阿里云镜像和 JitPack
    - 支持 Kotlin DSL 格式的 Gradle 配置

配置文件:
    Maven:
        ~/.m2/settings.xml
    Gradle:
        ./settings.gradle.kts
        ./build.gradle.kts

示例:
    > cd your_project_directory
    > python gfw_project.py
    [INFO] build.gradle.kts 已更新为使用阿里镜像。

注意:
    - 运行前建议备份原有配置文件
    - 需要在项目根目录下运行
    - 配置修改后需要重新同步项目
"""

import os
import logging

# 配置日志，设置日志级别为 INFO，并定义日志输出格式
# 日志格式包含日志级别和具体的日志信息
logging.basicConfig(level=logging.INFO, format='[%(levelname)s] %(message)s')

# 定义常量，存储阿里云 Maven 镜像的 URL，用于后续配置文件替换
ALIYUN_MAVEN_URL = "https://maven.aliyun.com/repository/public"
# 定义常量，存储 JitPack 的 URL，用于 Gradle 项目仓库配置
JITPACK_URL = "https://jitpack.io"

# 定义 Gradle 项目 settings.gradle.kts 文件中 pluginManagement 部分的配置模板
# 该模板将仓库配置为使用阿里云镜像和 Maven 中央仓库
SETTINGS_PLUGIN_MANAGEMENT_TEMPLATE = f"""
pluginManagement {{
    repositories {{
        gradlePluginPortal()
        maven {{ url = uri("{ALIYUN_MAVEN_URL}") }}
        mavenCentral()
    }}
}}
"""

# 定义 Gradle 项目 settings.gradle.kts 文件中 dependencyResolutionManagement 部分的配置模板
# 同样将仓库配置为使用阿里云镜像和 Maven 中央仓库
SETTINGS_DEPENDENCY_RESOLUTION_TEMPLATE = f"""
dependencyResolutionManagement {{
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {{
        maven {{ url = uri("{ALIYUN_MAVEN_URL}") }}
        mavenCentral()
        maven {{ url = uri("{JITPACK_URL}") }}
    }}
}}
"""

# 定义 Gradle 项目 build.gradle.kts 文件中 allprojects 部分的配置模板
# 配置仓库使用阿里云镜像和 Maven 中央仓库
BUILD_ALLPROJECTS_TEMPLATE = f"""
allprojects {{
    repositories {{
        maven {{ url = uri("{ALIYUN_MAVEN_URL}") }}
        mavenCentral()
        maven {{ url = uri("{JITPACK_URL}") }}
    }}
}}
"""

# 定义 Maven 项目 settings.xml 文件中镜像配置的模板
# 将所有仓库镜像为阿里云 Maven 镜像
MAVEN_MIRROR_TEMPLATE = f"""
    <mirrors>
        <mirror>
            <id>aliyunmaven</id>
            <mirrorOf>*</mirrorOf>
            <name>阿里云公共仓库</name>
            <url>{ALIYUN_MAVEN_URL}</url>
        </mirror>
    </mirrors>
"""


# 项目配置修改抽象基类
# 所有具体的项目配置修改器都将继承此类，并实现 modify_config 方法
class ProjectConfigModifier:
    def __init__(self, file_path):
        # 初始化时传入需要修改的配置文件路径
        self.file_path = file_path

    def modify_config(self):
        # 此方法需要在子类中具体实现，用于修改配置文件
        raise NotImplementedError("子类必须实现此方法")


# Maven 项目配置修改器，继承自 ProjectConfigModifier
class MavenProjectConfigModifier(ProjectConfigModifier):
    def modify_config(self):
        # 检查 Maven 的 settings.xml 文件是否存在
        if not os.path.exists(self.file_path):
            # 若文件不存在，记录错误日志
            logging.error("Maven settings.xml 文件不存在。")
            return
        try:
            # 以只读模式打开 settings.xml 文件并读取内容
            with open(self.file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            # 查找文件中 <mirrors> 标签的起始位置
            mirrors_start_index = content.find("<mirrors>")
            # 查找文件中 </mirrors> 标签的结束位置
            mirrors_end_index = content.find("</mirrors>")

            if mirrors_start_index != -1 and mirrors_end_index != -1:
                # 如果文件中已经存在 <mirrors> 标签，替换该标签内的内容
                new_content = content[:mirrors_start_index] + MAVEN_MIRROR_TEMPLATE + content[mirrors_end_index + len("</mirrors>"):]
            else:
                # 如果文件中不存在 <mirrors> 标签，查找 <profiles> 标签的位置
                profiles_index = content.find("<profiles>")
                if profiles_index != -1:
                    # 在 <profiles> 标签前插入镜像配置
                    new_content = content[:profiles_index] + MAVEN_MIRROR_TEMPLATE + content[profiles_index:]
                else:
                    # 如果文件中没有 <profiles> 标签，直接在文件末尾添加镜像配置
                    new_content = content + MAVEN_MIRROR_TEMPLATE

            # 以写入模式打开 settings.xml 文件，将修改后的内容写入
            with open(self.file_path, 'w', encoding='utf-8') as f:
                f.write(new_content)
            # 记录配置修改成功的日志
            logging.info("Maven settings.xml 已更新为使用阿里镜像。")
        except Exception as e:
            # 若修改过程中出现异常，记录错误日志
            logging.error(f"修改 Maven 配置文件时出错: {e}")


# Gradle 项目配置修改器（处理 settings.gradle.kts），继承自 ProjectConfigModifier
class GradleSettingsConfigModifier(ProjectConfigModifier):
    def modify_config(self):
        # 检查 Gradle 的 settings.gradle.kts 文件是否存在
        if not os.path.exists(self.file_path):
            # 若文件不存在，记录错误日志
            logging.error("Gradle settings.gradle.kts 文件不存在。")
            return
        try:
            # 以只读模式打开 settings.gradle.kts 文件并读取内容
            with open(self.file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            new_content = ""
            if "pluginManagement" in content:
                # 如果文件中已经存在 pluginManagement 部分，替换该部分内容
                new_content = content.replace("pluginManagement {", SETTINGS_PLUGIN_MANAGEMENT_TEMPLATE)
            else:
                # 如果文件中不存在 pluginManagement 部分，在文件开头添加该部分配置
                new_content = SETTINGS_PLUGIN_MANAGEMENT_TEMPLATE + '\n' + content

            if "dependencyResolutionManagement" in new_content:
                # 如果文件中已经存在 dependencyResolutionManagement 部分，替换该部分内容
                new_content = new_content.replace("dependencyResolutionManagement {", SETTINGS_DEPENDENCY_RESOLUTION_TEMPLATE)
            else:
                # 如果文件中不存在 dependencyResolutionManagement 部分，在文件中添加该部分配置
                new_content += '\n' + SETTINGS_DEPENDENCY_RESOLUTION_TEMPLATE

            # 以写入模式打开 settings.gradle.kts 文件，将修改后的内容写入
            with open(self.file_path, 'w', encoding='utf-8') as f:
                f.write(new_content)
            # 记录配置修改成功的日志
            logging.info("settings.gradle.kts 已更新为使用阿里镜像。")
        except Exception as e:
            # 若修改过程中出现异常，记录错误日志
            logging.error(f"修改 Gradle settings.gradle.kts 配置文件时出错: {e}")


# Gradle 项目配置修改器（处理 build.gradle.kts），继承自 ProjectConfigModifier
class GradleBuildConfigModifier(ProjectConfigModifier):
    def modify_config(self):
        # 检查 Gradle 的 build.gradle.kts 文件是否存在
        if not os.path.exists(self.file_path):
            # 若文件不存在，记录错误日志
            logging.error("Gradle build.gradle.kts 文件不存在。")
            return
        try:
            # 以只读模式打开 build.gradle.kts 文件并读取内容
            with open(self.file_path, 'r', encoding='utf-8') as f:
                content = f.read()
            if "allprojects" in content:
                # 如果文件中已经存在 allprojects 部分，替换该部分内容
                new_content = content.replace("allprojects {", BUILD_ALLPROJECTS_TEMPLATE)
            else:
                # 如果文件中不存在 allprojects 部分，在文件开头添加该部分配置
                new_content = BUILD_ALLPROJECTS_TEMPLATE + '\n' + content

            # 以写入模式打开 build.gradle.kts 文件，将修改后的内容写入
            with open(self.file_path, 'w', encoding='utf-8') as f:
                f.write(new_content)
            # 记录配置修改成功的日志
            logging.info("build.gradle.kts 已更新为使用阿里镜像。")
        except Exception as e:
            # 若修改过程中出现异常，记录错误日志
            logging.error(f"修改 Gradle build.gradle.kts 配置文件时出错: {e}")


# 项目类型检测器
class ProjectTypeDetector:
    def __init__(self, project_dir):
        # 初始化时传入项目所在目录
        self.project_dir = project_dir
        # 构建 Maven settings.xml 文件的完整路径
        self.maven_settings_file = os.path.join(os.path.expanduser("~"), ".m2", "settings.xml")
        # 构建 Gradle settings.gradle.kts 文件的完整路径
        self.gradle_settings_file = os.path.join(project_dir, "settings.gradle.kts")
        # 构建 Gradle build.gradle.kts 文件的完整路径
        self.gradle_build_file = os.path.join(project_dir, "build.gradle.kts")

    def detect(self):
        # 检查 Maven settings.xml 文件是否存在
        if os.path.exists(self.maven_settings_file):
            # 若存在，返回 Maven 项目配置修改器
            return MavenProjectConfigModifier(self.maven_settings_file)
        # 检查 Gradle settings.gradle.kts 文件是否存在
        elif os.path.exists(self.gradle_settings_file):
            # 若存在，返回 Gradle settings.gradle.kts 配置修改器
            return GradleSettingsConfigModifier(self.gradle_settings_file)
        # 检查 Gradle build.gradle.kts 文件是否存在
        elif os.path.exists(self.gradle_build_file):
            # 若存在，返回 Gradle build.gradle.kts 配置修改器
            return GradleBuildConfigModifier(self.gradle_build_file)
        # 若以上文件都不存在，返回 None
        return None


if __name__ == "__main__":
    # 获取当前项目所在目录
    project_dir = os.getcwd()
    # 创建项目类型检测器实例
    detector = ProjectTypeDetector(project_dir)
    # 调用 detect 方法检测项目类型并获取相应的配置修改器
    modifier = detector.detect()

    if modifier:
        # 若存在合适的配置修改器，调用其 modify_config 方法进行配置修改
        modifier.modify_config()
    else:
        # 若未找到合适的配置修改器，记录错误日志
        logging.error("未找到合适的 Maven 或 Gradle 配置文件。")